﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;

namespace SystemServer
{
    class Listener
    {
        private class ClientInfo
        {
            public Thread Thread;
            public Socket Socket;
        }

        private int _port;
        private int _num=0;
        private Socket _serverSocket;
        private Thread _acceptThread;
        private List<ClientInfo> _clients = new List<ClientInfo>();

        public Listener(int port)
        {
            _port = port;
        }

        public bool Start()
        {
            IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName());
            IPEndPoint endPoint = new IPEndPoint(localMachineInfo.AddressList[1], _port);
            Console.WriteLine("End point: " + endPoint.ToString());
            _serverSocket = new Socket(endPoint.Address.AddressFamily,
                                        SocketType.Stream, ProtocolType.Tcp);
            _serverSocket.Bind(endPoint);
            _serverSocket.Listen((int)SocketOptionName.MaxConnections);
            _acceptThread = new Thread(AcceptConnections);
            _acceptThread.IsBackground = true;
            _acceptThread.Start();
            return true;
        }

        private void AcceptConnections()
        {
            Console.WriteLine("Server Started");
            while (true)
            {
                Socket socket = _serverSocket.Accept();
                ClientInfo conn = new ClientInfo();
                conn.Socket = socket;
                conn.Thread = new Thread(ProcessConnection);
                conn.Thread.IsBackground = true;
                conn.Thread.Start(conn);
                Console.WriteLine("New connection accepted");
                _num++;
                _clients.Add(conn);
            }

        }

        private void ProcessConnection(object state)
        {
            ClientInfo conn = (ClientInfo)state;
            byte[] buffer = new byte[255];
            try
            {
                while (true)
                {
                    int bytesRead = conn.Socket.Receive(buffer);
                    if (bytesRead > 0)
                    {
                        Console.WriteLine("Incoming message: " + buffer.ToString());
                        lock (_clients)
                        {
                            foreach (ClientInfo cli in _clients)
                            {
                               // if (cli != conn)
                              //  {
                                    cli.Socket.Send(buffer, bytesRead, SocketFlags.None);
                                    Console.WriteLine("Transmit data to:" + cli.Socket.LocalEndPoint.ToString());
                              //  }
                            }
                        }
                    }
                    else if (bytesRead == 0) return;
                }
            }
            catch (SocketException exc)
            {
                Console.WriteLine("Socket exception: " +
                    exc.SocketErrorCode);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Exception: " + exc);
            }
            finally
            {
                conn.Socket.Close();
                lock (_clients) _clients.Remove(conn);
            }
        }
    }
}
